/*
 * Copyright (c) 2009, Jan Pastor. All Rights Reserved.
 */

package sk.jp.jitag.dao.db4o;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.Predicate;

import sk.jp.commons.utils.ExceptionUtils;

/**
 * Superclass of all persisted entities.
 */
public abstract class BaseEntity {

    /**
     * Check if given value is not null.
     * @param column
     * @param value
     * @throws EntityConstraintException if value is null.
     */
    protected void checkNotNull(Column column, Object value){
        if(value == null){
            throw new EntityConstraintException("Value can not be null",
                                                "sk.jp.jitag.dao.db4o.BaseEntity.err.001",
                            ExceptionUtils.paramsToMap("columnName", column.getName()));
        }
    }

    /**
     * Check if given value is not empty string.
     * @param column
     * @param value value to check. Result is unspecified if is null.
     * @throws EntityConstraintException if value is empty string.
     */
    protected void checkNotEmpty(Column column, String value){
        if("".equals(value)){
            throw new EntityConstraintException("Value can not be empty",
                                                "sk.jp.jitag.dao.db4o.BaseEntity.err.002",
                            ExceptionUtils.paramsToMap("columnName", column.getName()));
        }
    }

    /**
     * Check if given value is not null and not empty.
     * @param column
     * @param value
     * @throws EntityConstraintException if value is null or empty string.
     */
    protected void checkNotNullNotEmpty(Column column, String value){
        checkNotNull(column, value);
        checkNotEmpty(column, value);
    }

    /**
     * Check if given value has length greater than specified length.
     * @param column
     * @param value value to check. If null, check is allways success.
     * @param maxlen
     * @throws EntityConstraintException if value has length that is greater
     * than specified length.
     */
    protected void checkMaxLen(Column column, String value, int maxlen){
        if(value != null){
            if(value.length() > maxlen){
                throw new EntityConstraintException("Value length is too long",
                                                    "sk.jp.jitag.dao.db4o.BaseEntity.err.003",
                                ExceptionUtils.paramsToMap("columnName", column.getName(),
                                                           "valueLength", value.length(),
                                                           "maxLength", maxlen));
            }
        }
    }

    /**
     * Check if given value has length greater than specified length.
     * @param column
     * @param value value to check. If null, check is allways success.
     * @param max
     * @throws EntityConstraintException if value has length that is greater
     * than specified length.
     */
    protected void checkMaxLen(Column column, Number value, long max){
        if(value != null){
            if(value.longValue() > max){
                throw new EntityConstraintException("Value is too big",
                                                    "sk.jp.jitag.dao.db4o.BaseEntity.err.004",
                                ExceptionUtils.paramsToMap("columnName", column.getName(),
                                                           "valueLength", value,
                                                           "maxLength", max));
            }
        }
    }

    /**
     * Check if given value has length smaller than specified length.
     * @param column
     * @param value value to check. If null, check is allways success.
     * @param min
     * @throws EntityConstraintException if value has length that is smaller
     * than specified length.
     */
    protected void checkMinLen(Column column, Number value, int min){
        if(value != null){
            if(value.longValue() < min){
                throw new EntityConstraintException("Value is too small",
                                                    "sk.jp.jitag.dao.db4o.BaseEntity.err.005",
                                ExceptionUtils.paramsToMap("columnName", column.getName(),
                                                           "valueLength", value,
                                                           "minLength", min));
            }
        }
    }

    /**
     * See {@link CollectionsFactory#createList()} for details.
     */
    protected <T> List<T> createList(){
        return CollectionsFactory.createList();
    }

    /**
     * See {@link CollectionsFactory#createList(Collection)} for details.
     */
    protected <T> List<T> createList(Collection<T> collection){
        return CollectionsFactory.createList(collection);
    }

    /**
     * See {@link CollectionsFactory#createList(int)} for details.
     */
    protected <T> List<T> createList(int initialSize){
        return CollectionsFactory.createList(initialSize);
    }

    /**
     * See {@link CollectionsFactory#createMap()} for details.
     */
    protected <K, V> Map<K, V> createMap(){
        return CollectionsFactory.createMap();
    }

    protected <T extends BaseEnum> T getActiveEnumInstance(final T enumInstance,
                                                           ObjectContainer container){
        ObjectSet<T> res = container.query(new Predicate<T>() {
                @Override
                public boolean match(T candidate) {
                    return enumInstance.getCode().equals(candidate.getCode());
                }
            });
        return Db4oUtils.getOneRequired(res);        
    }

    /**
     * All subclasses must implement toString method that can be used for
     * entity state dump.
     * @return entity state in text form.
     */
    public abstract String toString();

}
